/*
Copyright 2007-2012 Selenium committers

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

package org.openqa.selenium.remote;

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;

import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.Beta;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.interactions.HasInputDevices;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.interactions.Keyboard;
import org.openqa.selenium.interactions.Mouse;
import org.openqa.selenium.Platform;
import org.openqa.selenium.Point;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.UnsupportedCommandException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.FindsByClassName;
import org.openqa.selenium.internal.FindsByCssSelector;
import org.openqa.selenium.internal.FindsById;
import org.openqa.selenium.internal.FindsByLinkText;
import org.openqa.selenium.internal.FindsByName;
import org.openqa.selenium.internal.FindsByTagName;
import org.openqa.selenium.internal.FindsByXPath;
import org.openqa.selenium.logging.LocalLogs;
import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingHandler;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.logging.Logs;
import org.openqa.selenium.logging.NeedsLocalLogs;
import org.openqa.selenium.remote.internal.JsonToWebElementConverter;
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
import org.openqa.selenium.security.Credentials;

import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/*import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.IRational;*/

public class RemoteWebDriver implements WebDriver, JavascriptExecutor,
FindsById, FindsByClassName, FindsByLinkText, FindsByName,
FindsByCssSelector, FindsByTagName, FindsByXPath,
HasInputDevices, HasCapabilities,TakesScreenshot {

	// TODO(dawagner): This static logger should be unified with the per-instance localLogs
	private static final Logger logger = Logger.getLogger(RemoteWebDriver.class.getName());
	private Level level = Level.FINE;

	private final ErrorHandler errorHandler = new ErrorHandler();

	private CommandExecutor executor;
	private Capabilities capabilities;
	private SessionId sessionId;
	private FileDetector fileDetector = new UselessFileDetector();
	private ExecuteMethod executeMethod;

	private JsonToWebElementConverter converter;

	private RemoteKeyboard keyboard;
	private RemoteMouse mouse;
	private Logs remoteLogs;
	private LocalLogs localLogs;

	//private static IRational FRAME_RATE = IRational.make(3, 1);

	public static boolean videoVar=true;

	private String startedAt="";
	private String endedAt="";
	private Map<String,?> params;

	private String browser="";

	public String getDate()
	{
		Date dNow = new Date( );
		SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh'h'mm'm'ss's' a zzz");
		String temp=ft.format(dNow);
		return temp;
	}

	private final String resultFolder="results\\";
	// For cglib
	protected RemoteWebDriver() {
		init(new DesiredCapabilities(), null);
	}

	public RemoteWebDriver(CommandExecutor executor, Capabilities desiredCapabilities,
			Capabilities requiredCapabilities) {
		this.executor = executor;

		init(desiredCapabilities, requiredCapabilities);

		if (executor instanceof NeedsLocalLogs) {
			((NeedsLocalLogs)executor).setLocalLogs(localLogs);
		}
		startClient();
		startSession(desiredCapabilities, requiredCapabilities);
	}

	public RemoteWebDriver(CommandExecutor executor, Capabilities desiredCapabilities) {
		this(executor, desiredCapabilities, null);
	}

	public RemoteWebDriver(Capabilities desiredCapabilities) {
		this((URL) null, desiredCapabilities);
	}

	public RemoteWebDriver(URL remoteAddress, Capabilities desiredCapabilities,
			Capabilities requiredCapabilities) {
		this(new HttpCommandExecutor(remoteAddress), desiredCapabilities,
				requiredCapabilities);
	}

	public RemoteWebDriver(URL remoteAddress, Capabilities desiredCapabilities) {
		this(new HttpCommandExecutor(remoteAddress), desiredCapabilities, null);
	}

	private void init(Capabilities desiredCapabilities, Capabilities requiredCapabilities) {
		logger.addHandler(LoggingHandler.getInstance());

		converter = new JsonToWebElementConverter(this);
		executeMethod = new RemoteExecuteMethod(this);
		keyboard = new RemoteKeyboard(executeMethod);
		mouse = new RemoteMouse(executeMethod);

		ImmutableSet.Builder<String> builder = new ImmutableSet.Builder<String>();

		boolean isProfilingEnabled = desiredCapabilities != null &&
		desiredCapabilities.is(CapabilityType.ENABLE_PROFILING_CAPABILITY);
		if (requiredCapabilities != null && requiredCapabilities.getCapability(
				CapabilityType.ENABLE_PROFILING_CAPABILITY) != null) {
			isProfilingEnabled = requiredCapabilities.is(CapabilityType.ENABLE_PROFILING_CAPABILITY);
		}
		if (isProfilingEnabled) {
			builder.add(LogType.PROFILER);
		}

		LoggingPreferences mergedLoggingPrefs = new LoggingPreferences();    
		if (desiredCapabilities != null) {
			mergedLoggingPrefs.addPreferences((LoggingPreferences)desiredCapabilities.getCapability(
					CapabilityType.LOGGING_PREFS));  
		}
		if (requiredCapabilities != null) {
			mergedLoggingPrefs.addPreferences((LoggingPreferences)requiredCapabilities.getCapability(
					CapabilityType.LOGGING_PREFS));
		}
		if ((mergedLoggingPrefs.getEnabledLogTypes().contains(LogType.CLIENT) &&
				mergedLoggingPrefs.getLevel(LogType.CLIENT) != Level.OFF) ||
				!mergedLoggingPrefs.getEnabledLogTypes().contains(LogType.CLIENT)) {
			builder.add(LogType.CLIENT);
		}

		Set<String> logTypesToInclude = builder.build();

		LocalLogs performanceLogger = LocalLogs.getStoringLoggerInstance(logTypesToInclude);
		LocalLogs clientLogs = LocalLogs.getHandlerBasedLoggerInstance(LoggingHandler.getInstance(),
				logTypesToInclude);
		localLogs = LocalLogs.getCombinedLogsHolder(clientLogs, performanceLogger);
		remoteLogs = new RemoteLogs(executeMethod, localLogs);
	}

	/**
	 * Set the file detector to be used when sending keyboard input. By default, this is set to a file
	 * detector that does nothing.
	 *
	 * @param detector The detector to use. Must not be null.
	 * @see FileDetector
	 * @see LocalFileDetector
	 * @see UselessFileDetector
	 */
	public void setFileDetector(FileDetector detector) {
		if (detector == null) {
			throw new WebDriverException("You may not set a file detector that is null");
		}
		fileDetector = detector;
	}

	public SessionId getSessionId() {
		return sessionId;
	}

	protected void setSessionId(String opaqueKey) {
		sessionId = new SessionId(opaqueKey);
	}

	protected void startSession(Capabilities desiredCapabilities) {
		startSession(desiredCapabilities, null);
	}

	@SuppressWarnings({"unchecked"})
	protected void startSession(Capabilities desiredCapabilities,
			Capabilities requiredCapabilities) {

		ImmutableMap.Builder<String, Capabilities> paramBuilder =
			new ImmutableMap.Builder<String, Capabilities>();
		paramBuilder.put("desiredCapabilities", desiredCapabilities);    
		if (requiredCapabilities != null) {
			paramBuilder.put("requiredCapabilities", requiredCapabilities);
		}
		Map<String, ?> parameters = paramBuilder.build();

		Response response = execute(DriverCommand.NEW_SESSION, parameters);

		//***************START VIDEO RECORDING*****************
		Date dNow = new Date( );
		SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
		startedAt=ft.format(dNow);

		//********Writing to started.properties****
		Properties prop = new Properties();
		try 
		{
			//set the properties value
			prop.setProperty("started",startedAt);
			//save properties to project root folder
			prop.store(new FileOutputStream(resultFolder+response.getSessionId()+"\\started.properties"), null);

		} 
		catch (IOException ex) {
			ex.printStackTrace();
		}
		videoVar=true;
		//recrdVideo(response.getSessionId());

		//*****************************************************

		Map<String, Object> rawCapabilities = (Map<String, Object>) response.getValue();
		DesiredCapabilities returnedCapabilities = new DesiredCapabilities();
		for (Map.Entry<String, Object> entry : rawCapabilities.entrySet()) {
			// Handle the platform later
			if (CapabilityType.PLATFORM.equals(entry.getKey())) {
				continue;
			}
			returnedCapabilities.setCapability(entry.getKey(), entry.getValue());
		}
		String platformString = (String) rawCapabilities.get(CapabilityType.PLATFORM);
		Platform platform;
		try {
			if (platformString == null || "".equals(platformString)) {
				platform = Platform.ANY;
			} else {
				platform = Platform.valueOf(platformString);
			}
		} catch (IllegalArgumentException e) {
			// The server probably responded with a name matching the os.name
			// system property. Try to recover and parse this.
			platform = Platform.extractFromSysProperty(platformString);
		}
		returnedCapabilities.setPlatform(platform);

		capabilities = returnedCapabilities;
		sessionId = new SessionId(response.getSessionId());
	}

	/**
	 * Method called before {@link #startSession(Capabilities) starting a new session}. The default
	 * implementation is a no-op, but subtypes should override this method to define custom behavior.
	 */
	protected void startClient() {
	}

	/**
	 * Method called after executing a {@link #quit()} command. Subtypes
	 */
	protected void stopClient() {
	}

	public ErrorHandler getErrorHandler() {
		return errorHandler;
	}

	public CommandExecutor getCommandExecutor() {
		return executor;
	}

	protected void setCommandExecutor(CommandExecutor executor) {
		this.executor = executor;
	}

	public Capabilities getCapabilities() {
		return capabilities;
	}

	public void get(String url) {
		execute(DriverCommand.GET, ImmutableMap.of("url", url));
	}

	public RemoteStatus getRemoteStatus() {
		Response response = execute(DriverCommand.STATUS);
		return new RemoteStatus((Map<String, Object>) response.getValue());
	}

	public String getTitle() {
		Response response = execute(DriverCommand.GET_TITLE);
		Object value = response.getValue();
		return value == null ? "" : value.toString();
	}

	public String getCurrentUrl() {
		return execute(DriverCommand.GET_CURRENT_URL).getValue().toString();
	}

	public List<WebElement> findElements(By by) {
		return by.findElements(this);
	}

	public WebElement findElement(By by) {
		return by.findElement(this);
	}

	protected WebElement findElement(String by, String using) {
		if (using == null) {
			throw new IllegalArgumentException("Cannot find elements when the selector is null.");
		}

		Response response = execute(DriverCommand.FIND_ELEMENT,
				ImmutableMap.of("using", by, "value", using));
		Object value = response.getValue();
		WebElement element;
		try {
			element = (WebElement) value;
		} catch (ClassCastException ex) {
			throw new WebDriverException("Returned value cannot be converted to WebElement: " + value, ex);
		}
		setFoundBy(this, element, by, using);
		return element;
	}

	protected void setFoundBy(SearchContext context, WebElement element, String by, String using) {
		if (element instanceof RemoteWebElement) {
			((RemoteWebElement) element).setFoundBy(context, by, using);
		}
	}

	@SuppressWarnings("unchecked")
	protected List<WebElement> findElements(String by, String using) {
		if (using == null) {
			throw new IllegalArgumentException("Cannot find elements when the selector is null.");
		}

		Response response = execute(DriverCommand.FIND_ELEMENTS,
				ImmutableMap.of("using", by, "value", using));
		Object value = response.getValue();
		List<WebElement> allElements;
		try {
			allElements = (List<WebElement>) value;
		} catch (ClassCastException ex) {
			throw new WebDriverException("Returned value cannot be converted to List<WebElement>: " + value, ex);
		}
		for (WebElement element : allElements) {
			setFoundBy(this, element, by, using);
		}
		return allElements;
	}

	public WebElement findElementById(String using) {
		return findElement("id", using);
	}

	public List<WebElement> findElementsById(String using) {
		return findElements("id", using);
	}

	public WebElement findElementByLinkText(String using) {
		return findElement("link text", using);
	}

	public List<WebElement> findElementsByLinkText(String using) {
		return findElements("link text", using);
	}

	public WebElement findElementByPartialLinkText(String using) {
		return findElement("partial link text", using);
	}

	public List<WebElement> findElementsByPartialLinkText(String using) {
		return findElements("partial link text", using);
	}

	public WebElement findElementByTagName(String using) {
		return findElement("tag name", using);
	}

	public List<WebElement> findElementsByTagName(String using) {
		return findElements("tag name", using);
	}

	public WebElement findElementByName(String using) {
		return findElement("name", using);
	}

	public List<WebElement> findElementsByName(String using) {
		return findElements("name", using);
	}

	public WebElement findElementByClassName(String using) {
		return findElement("class name", using);
	}

	public List<WebElement> findElementsByClassName(String using) {
		return findElements("class name", using);
	}

	public WebElement findElementByCssSelector(String using) {
		return findElement("css selector", using);
	}

	public List<WebElement> findElementsByCssSelector(String using) {
		return findElements("css selector", using);
	}

	public WebElement findElementByXPath(String using) {
		return findElement("xpath", using);
	}

	public List<WebElement> findElementsByXPath(String using) {
		return findElements("xpath", using);
	}

	// Misc

	public String getPageSource() {
		return (String) execute(DriverCommand.GET_PAGE_SOURCE).getValue();
	}

	public void close() {
		execute(DriverCommand.CLOSE);
	}

	public void quit() {
		try {
			execute(DriverCommand.QUIT);
		} finally {
			sessionId = null;
			stopClient();
		}
	}

	@SuppressWarnings({"unchecked"})
	public Set<String> getWindowHandles() {
		Response response = execute(DriverCommand.GET_WINDOW_HANDLES);
		Object value = response.getValue();
		try {
			List<String> returnedValues = (List<String>) value;
			return new LinkedHashSet<String>(returnedValues);
		} catch (ClassCastException ex) {
			throw new WebDriverException("Returned value cannot be converted to List<String>: " + value, ex);
		}
	}

	public String getWindowHandle() {
		return String.valueOf(execute(DriverCommand.GET_CURRENT_WINDOW_HANDLE).getValue());
	}

	public Object executeScript(String script, Object... args) {
		if (!capabilities.isJavascriptEnabled()) {
			throw new UnsupportedOperationException(
			"You must be using an underlying instance of WebDriver that supports executing javascript");
		}

		// Escape the quote marks
		script = script.replaceAll("\"", "\\\"");

		Iterable<Object> convertedArgs = Iterables.transform(
				Lists.newArrayList(args), new WebElementToJsonConverter());

		Map<String, ?> params = ImmutableMap.of(
				"script", script,
				"args", Lists.newArrayList(convertedArgs));

		return execute(DriverCommand.EXECUTE_SCRIPT, params).getValue();
	}

	public Object executeAsyncScript(String script, Object... args) {
		if (!isJavascriptEnabled()) {
			throw new UnsupportedOperationException("You must be using an underlying instance of " +
			"WebDriver that supports executing javascript");
		}

		// Escape the quote marks
		script = script.replaceAll("\"", "\\\"");

		Iterable<Object> convertedArgs = Iterables.transform(
				Lists.newArrayList(args), new WebElementToJsonConverter());

		Map<String, ?> params = ImmutableMap.of(
				"script", script, "args", Lists.newArrayList(convertedArgs));

		return execute(DriverCommand.EXECUTE_ASYNC_SCRIPT, params).getValue();
	}

	private boolean isJavascriptEnabled() {
		return capabilities.isJavascriptEnabled();
	}

	public TargetLocator switchTo() {
		return new RemoteTargetLocator();
	}

	public Navigation navigate() {
		return new RemoteNavigation();
	}

	public Options manage() {
		return new RemoteWebDriverOptions();
	}

	protected void setElementConverter(JsonToWebElementConverter converter) {
		this.converter = converter;
	}

	protected JsonToWebElementConverter getElementConverter() {
		return converter;
	}

	/**
	 * Sets the RemoteWebDriver's client log level.
	 *
	 * @param level The log level to use.
	 */
	public void setLogLevel(Level level) {
		this.level = level;
	}

	protected Response execute(String driverCommand, Map<String, ?> parameters) {
		Command command = new Command(sessionId, driverCommand, parameters);
		Response response;


		long start = System.currentTimeMillis();
		String currentName = Thread.currentThread().getName();
		Thread.currentThread().setName("Forwarding " + driverCommand + " on session " + sessionId +
		" to remote");
		//To find stop of a command
		long stop=0;

		try {

			//Taking screen shot if the command is quit before execution
			if(driverCommand.equals(DriverCommand.QUIT))
				takeScreenShot(command,start,sessionId.toString());

			log(sessionId, command.getName(), command, When.BEFORE);
			response = executor.execute(command);

			if(driverCommand.equals(DriverCommand.NEW_SESSION))
			{
				Map<String,?> tempMap= (Map<String,?>)response.getValue();
				browser = (String)tempMap.get("browserName");
			}
			//**********TAKE SCREEN SHOT*****

			//Highlight Element
			if(command.getName()==DriverCommand.FIND_ELEMENT)
			{
				Map<String,?> exceptionResponse = (Map<String,?>)response.getValue();
				Object dispValue=exceptionResponse.get("message");
				if(dispValue==null)
					executeScript("arguments[0].setAttribute('style', arguments[1]);",response.getValue(), "color: red; border: 2px solid red;");
			}

			//Screen shot for commands other than quit
			if(!driverCommand.equals(DriverCommand.QUIT))
				takeScreenShot(command,start,response.getSessionId());

			//Remove high light
			if(command.getName()==DriverCommand.FIND_ELEMENT)
			{
				Map<String,?> exceptionResponse = (Map<String,?>)response.getValue();
				Object dispValue=exceptionResponse.get("message");
				if(dispValue==null)
					executeScript("arguments[0].setAttribute('style', arguments[1]);", response.getValue(), "");
			}	

			//Calculating end of each command
			stop = System.currentTimeMillis();

			//Calculating when the session ends
			if(driverCommand.equals(DriverCommand.QUIT))
			{
				Date dNow = new Date();
				SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
				endedAt=ft.format(dNow);
				//********Writing to ended.properties****
				Properties prop = new Properties();

				try 
				{
					//set the properties value
					prop.setProperty("ended",endedAt);
					//save properties to project root folder
					prop.store(new FileOutputStream(resultFolder+response.getSessionId()+"\\ended.properties"), null);

				} catch (IOException ex) {
					ex.printStackTrace();
				}

			}

			//*******************************


			log(sessionId, command.getName(), command, When.AFTER);

			if (response == null) {
				return null;
			}


			// Unwrap the response value by converting any JSON objects of the form
			// {"ELEMENT": id} to RemoteWebElements.
			Object value = converter.apply(response.getValue());
			response.setValue(value);


		} catch (SessionNotFoundException e){
			throw e;
		} catch (Exception e) 
		{
			log(sessionId, command.getName(), command, When.EXCEPTION);
			String errorMessage = "Error communicating with the remote browser. " +
			"It may have died.";
			if (driverCommand.equals(DriverCommand.NEW_SESSION)) {
				errorMessage = "Could not start a new session. Possible causes are " +
				"invalid address of the remote server or browser start-up failure.";
			}
			throw new UnreachableBrowserException(errorMessage, e);
		} 
		finally 
		{
			Thread.currentThread().setName(currentName);
		}

		try 
		{
			errorHandler.throwIfResponseFailed(response, System.currentTimeMillis() - start);
		} 
		catch (WebDriverException ex) 
		{
			createTableData(response.getSessionId(), command.getName(), response, start, stop, parameters,true);
			ex.addInfo(WebDriverException.DRIVER_INFO, this.getClass().getName());
			if (getSessionId() != null) {
				ex.addInfo(WebDriverException.SESSION_ID, getSessionId().toString());
			}
			if (getCapabilities() != null) 
			{
				ex.addInfo("Capabilities", getCapabilities().toString());

			}

			//***********Exceptions to Log.txt************
			try
			{ 


				File dir = new File(resultFolder+response.getSessionId());
				File f= new File(resultFolder+response.getSessionId()+"\\log.txt");

				if(!dir.exists())
					dir.mkdirs();

				if(!f.exists())
					f.createNewFile();

				FileWriter fr= new FileWriter(f,true);
				BufferedWriter bufferWritter = new BufferedWriter(fr);

				bufferWritter.newLine();
				bufferWritter.write("Exception"+ex.toString());

				bufferWritter.flush();
				bufferWritter.close();

			}
			catch(IOException e){logger.log(level, "Exception:Error Writnig Exception to file " );}
			//*****************************************

			Throwables.propagate(ex);



		}

		//*****************************************
		try 
		{

			File dir = new File(resultFolder+response.getSessionId());
			File f= new File(resultFolder+response.getSessionId()+"\\log.txt");

			if(!dir.exists())
				dir.mkdirs();

			if(!f.exists())
				f.createNewFile();

			FileWriter fr= new FileWriter(f,true);
			BufferedWriter bufferWritter = new BufferedWriter(fr);

			bufferWritter.newLine();
			bufferWritter.write("--------------------------");
			bufferWritter.newLine();
			bufferWritter.write("Command:"+driverCommand);
			bufferWritter.newLine();
			bufferWritter.write("Start:"+start);
			if(stop>0)
			{
				bufferWritter.newLine();
				bufferWritter.write("Stop:"+stop);
			}

			bufferWritter.newLine();
			bufferWritter.write("**Params**");
			for (Map.Entry<String, ?> entry : parameters.entrySet()) {
				bufferWritter.newLine();
				bufferWritter.write("Key = " + entry.getKey() + ", Value = " + entry.getValue());
			}

			bufferWritter.newLine();
			bufferWritter.write("Status:"+response.getStatus());
			bufferWritter.newLine();
			bufferWritter.write("Response Object:"+response.getValue());



			if(driverCommand.equals(DriverCommand.NEW_SESSION))
			{


				Map<String,?> temp= (Map<String,?>)response.getValue();
				bufferWritter.newLine();
				bufferWritter.write("Platform:"+temp.get("platform"));
				bufferWritter.newLine();
				bufferWritter.write("Browser:"+temp.get("browserName"));
				bufferWritter.newLine();
				bufferWritter.write("Version:"+temp.get("version"));



				//********Writing to config.properties****
				Properties prop = new Properties();

				try 
				{
					//set the properties value
					prop.setProperty("sessionId",response.getSessionId());
					prop.setProperty("platform",(String)temp.get("platform"));
					prop.setProperty("browser",(String)temp.get("browserName"));
					prop.setProperty("version",(String)temp.get("version"));


					//save properties to project root folder
					prop.store(new FileOutputStream(resultFolder+response.getSessionId()+"\\config.properties"), null);

				} catch (IOException ex) {
					ex.printStackTrace();
				}


			}

			bufferWritter.newLine();
			bufferWritter.write("--------------------------");



			bufferWritter.flush();
			bufferWritter.close();

			//***Creating each rows for each command except New Session*****
			if(!driverCommand.equals(DriverCommand.NEW_SESSION)&&!driverCommand.equals(DriverCommand.SCREENSHOT)&&!driverCommand.equals(DriverCommand.EXECUTE_SCRIPT))
				createTableData(response.getSessionId(), driverCommand, response, start, stop,parameters,false);

			//***************************************


			//******STOP VIDEO RECORDING***********
			if(driverCommand.equals(DriverCommand.QUIT))
			{
				videoVar=false;
				//Create final report
				createHtmlReport(response.getSessionId());
			}
			//*************************************


		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//*****************************************

		return response;
	}

	protected Response execute(String command) {
		return execute(command, ImmutableMap.<String, Object>of());
	}

	protected ExecuteMethod getExecuteMethod() {
		return executeMethod;
	}

	public Keyboard getKeyboard() {
		return keyboard;
	}

	public Mouse getMouse() {
		return mouse;
	}

	/**
	 * Override this to be notified at key points in the execution of a command.
	 *
	 * @param sessionId   the session id.
	 * @param commandName the command that is being executed.
	 * @param toLog       any data that might be interesting.
	 * @throws IOException 
	 */
	protected void log(SessionId sessionId, String commandName, Object toLog, When when)  {
		String text = "" + toLog;
		if (commandName.equals(DriverCommand.EXECUTE_SCRIPT)
				|| commandName.equals(DriverCommand.EXECUTE_ASYNC_SCRIPT)) {
			if (text.length() > 100 && Boolean.getBoolean("webdriver.remote.shorten_log_messages")) {
				text = text.substring(0, 100) + "...";
			}
		}
		switch(when) {
		case BEFORE:
			logger.log(level, "Executing: " + commandName + " " + text);
			break;
		case AFTER:
			logger.log(level, "Executed: " + text);
			break;
		case EXCEPTION:
			logger.log(level, "Exception: " + text);

			break;
		default:
			logger.log(level, text);
			break;
		}
	}

	public FileDetector getFileDetector() {
		return fileDetector;
	}


	/*public void recrdVideo(final String sessionId)
	{
		new Thread(new Runnable() {

			@Override
			public void run() {
				try
				{
					File dir= new File(resultFolder+sessionId);
					if(!dir.exists())
						dir.mkdirs();

					String outFile=resultFolder+sessionId+"\\video.flv";


					Robot robot = new Robot();
					Toolkit toolkit = Toolkit.getDefaultToolkit();
					Rectangle screenBounds = new Rectangle(toolkit.getScreenSize());

					IMediaWriter writer = ToolFactory.makeWriter(outFile);

					writer.addVideoStream(0, 0, FRAME_RATE, screenBounds.width, screenBounds.height);

					long startTime = System.nanoTime();

					while(videoVar)
					{

						BufferedImage screen = robot.createScreenCapture(screenBounds);

						BufferedImage bgrScreen = convertToType(screen, 5);

						writer.encodeVideo(0, bgrScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS);

						//System.out.println("encoded image: "+count);

						Thread.sleep((long)(1000.0D / FRAME_RATE.getDouble()));


					}
					writer.close();

				}
				catch (Throwable e)
				{
					System.err.println("an error occurred: " + e.getMessage());
				}

			}
		}).start();

	}*/


	public static BufferedImage convertToType(BufferedImage sourceImage, int targetType)
	{
		BufferedImage image;

		if (sourceImage.getType() == targetType) {
			image = sourceImage;
		}
		else
		{
			image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);

			image.getGraphics().drawImage(sourceImage, 0, 0, null);
		}

		return image;
	}


	public void takeScreenShot(Command command,Long commandStartTime,String sessionId) throws IOException, AWTException
	{
		//execute script is removed
		//Removing click and click element because of problem with alert
		//		||command.getName().equals(DriverCommand.CLICK)
		//		||command.getName().equals(DriverCommand.CLICK_ELEMENT)

		if(browser.equalsIgnoreCase("internet explorer"))
		{

			if(command.getName().equals(DriverCommand.GET)
					||command.getName().equals(DriverCommand.ACCEPT_ALERT)
					||command.getName().equals(DriverCommand.CLEAR_ELEMENT) 
					||command.getName().equals(DriverCommand.DISMISS_ALERT)
					||command.getName().equals(DriverCommand.DOUBLE_CLICK)
					||command.getName().equals(DriverCommand.ELEMENT_EQUALS)
					||command.getName().equals(DriverCommand.EXECUTE_ASYNC_SCRIPT)
					||command.getName().equals(DriverCommand.FIND_CHILD_ELEMENT)
					||command.getName().equals(DriverCommand.FIND_CHILD_ELEMENTS)
					||command.getName().equals(DriverCommand.FIND_ELEMENT)
					||command.getName().equals(DriverCommand.FIND_ELEMENTS)
					||command.getName().equals(DriverCommand.MAXIMIZE_WINDOW)
					||command.getName().equals(DriverCommand.MOUSE_DOWN)
					||command.getName().equals(DriverCommand.MOUSE_UP)
					||command.getName().equals(DriverCommand.MOVE_TO)
					||command.getName().equals(DriverCommand.SEND_KEYS_TO_ACTIVE_ELEMENT)
					||command.getName().equals(DriverCommand.SEND_KEYS_TO_ELEMENT)
					||command.getName().equals(DriverCommand.SWITCH_TO_FRAME)
					||command.getName().equals(DriverCommand.SWITCH_TO_WINDOW)
					||command.getName().equals(DriverCommand.QUIT)

			)
			{
				java.awt.Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
				Rectangle screenRectangle = new Rectangle(screenSize);
				Robot robot = new Robot();
				BufferedImage image = robot.createScreenCapture(screenRectangle);
				try
				{
					ImageIO.write(image, "png", new File(resultFolder+sessionId+"\\"+command.getName()+"_"+commandStartTime+".png"));
				}
				catch(FileNotFoundException e)
				{
					e.printStackTrace();
				}
			}

		}
		else
		{

			if(command.getName().equals(DriverCommand.GET)
					||command.getName().equals(DriverCommand.ACCEPT_ALERT)
					||command.getName().equals(DriverCommand.CLEAR_ELEMENT) 
					||command.getName().equals(DriverCommand.DISMISS_ALERT)
					||command.getName().equals(DriverCommand.DOUBLE_CLICK)
					||command.getName().equals(DriverCommand.ELEMENT_EQUALS)
					||command.getName().equals(DriverCommand.EXECUTE_ASYNC_SCRIPT)
					||command.getName().equals(DriverCommand.FIND_CHILD_ELEMENT)
					||command.getName().equals(DriverCommand.FIND_CHILD_ELEMENTS)
					||command.getName().equals(DriverCommand.FIND_ELEMENT)
					||command.getName().equals(DriverCommand.FIND_ELEMENTS)
					||command.getName().equals(DriverCommand.MAXIMIZE_WINDOW)
					||command.getName().equals(DriverCommand.MOUSE_DOWN)
					||command.getName().equals(DriverCommand.MOUSE_UP)
					||command.getName().equals(DriverCommand.MOVE_TO)
					||command.getName().equals(DriverCommand.SEND_KEYS_TO_ACTIVE_ELEMENT)
					||command.getName().equals(DriverCommand.SEND_KEYS_TO_ELEMENT)
					||command.getName().equals(DriverCommand.SWITCH_TO_FRAME)
					||command.getName().equals(DriverCommand.SWITCH_TO_WINDOW)
					||command.getName().equals(DriverCommand.QUIT)


			)
			{


				File rawfile= getScreenshotAs(OutputType.FILE);
				File outputFile = new File(resultFolder+sessionId+"\\"+command.getName()+"_"+commandStartTime+".png");

				try
				{
					FileUtils.copyFile(rawfile, outputFile);
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}

			}
		}
	}


	private void createTableData(String sessionId, String Command,Response response,long start, long stop, Map<String,?> params,boolean exception)
	{
		try 
		{

			File dir= new File(resultFolder+sessionId);
			if(!dir.exists())
				dir.mkdirs();

			String outFile=resultFolder+sessionId+"\\data.txt";
			File data = new File(outFile);
			if(!data.exists())
				data.createNewFile();


			FileWriter fr= new FileWriter(data,true);
			BufferedWriter bufferWritter = new BufferedWriter(fr);


			//Calculating duration
			long duration=stop-start;

			//Checking for screen shots
			String link="";
			File image= new File(resultFolder+sessionId+"\\"+Command+"_"+start+".png");
			if(image.exists())
			{
				link="<a href=\""+Command+"_"+start+".png" +"\">" +
				"<img src=\""+Command+"_"+start+".png\""+"height=\"20\""+"width=\"20\""+">"+
				"</a>";
			}


			//Retrieving Parameters
			String parameters="";
			for (Map.Entry<String, ?> entry : params.entrySet()) 
			{


				if(Command.equals(DriverCommand.SEND_KEYS_TO_ELEMENT))
				{
					if(entry.getValue() instanceof CharSequence[])
					{

						CharSequence[] temp = (CharSequence[])entry.getValue();
						String displayValue="";
						for(CharSequence c:temp)
						{
							displayValue+=c;
						}
						parameters+="</br><span style=\"font-size:11px; color:grey\">"+entry.getKey()+"="+displayValue+"</span>";
					}
					if (entry.getValue() instanceof String)
					{
						String temp= (String)entry.getValue();
						parameters+="</br><span style=\"font-size:11px; color:grey \">"+entry.getKey()+"="+temp+"</span>";
					}



				}
				else
				{
					parameters+="</br><span style=\"font-size:11px; color:grey \">"+entry.getKey()+"="+entry.getValue()+"</span>";
				}

			}


			//Checking if the response is an object of RemoteWebElement
			Object dispValue="";
			if(response.getValue() instanceof RemoteWebElement)
			{
				RemoteWebElement ele= (RemoteWebElement)response.getValue();
				dispValue=ele.getId();
			}
			else
			{
				dispValue=response.getValue();
			}

			//Checking if there is an exception and creating table data
			String dyanmic_part="";
			if(exception)
			{
				Map<String,?> exceptionResponse = (Map<String,?>)response.getValue();
				dispValue=exceptionResponse.get("message");
				dyanmic_part=
					"<tr height=\"60\" style=\"background-color: #F78181;\">"+
					"<td>"+Command+parameters+"</td>"+
					"<td>"+dispValue+"</td>"+
					"<td>"+duration+"<span style=\"color: grey;font-size: 9px;\">&nbsp;ms</span></td>"+
					"<td>"+link+"</td>"+

					"</tr>";
			}
			else
			{
				dyanmic_part=
					"<tr height=\"60\" style=\"background-color: #DDFFDD;\">"+
					"<td>"+Command+parameters+"</td>"+
					"<td>"+dispValue+"</td>"+
					"<td>"+duration+"<span style=\"color: grey;font-size: 9px;\">&nbsp;ms</span></td>"+
					"<td>"+link+"</td>"+

					"</tr>";

			}
			bufferWritter.write(dyanmic_part);
			bufferWritter.flush();
			bufferWritter.close();

		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}

	private void createCss(String sessionId){

		String css= 


			"body{font-family: verdana;}"+

			"#main_div" +
			"{" +
			"	height: auto;width:800px;min-height: 500px;margin-left: auto;margin-right: auto;margin-top: 50px;"+

			"border-top: #faac58 thin dotted;" +
			"border-bottom: #faac58 thin dotted;" +
			"border-left: #faac58 thin dotted;" +
			"border-right: #faac58 thin dotted;" +
			"}"+


			"#inner_div" +
			"{" +
			"	height: auto;" +
			"	width: 750px;" +
			"	min-height: 450px;" +
			"	margin-left: auto;" +
			"	margin-right: auto;" +
			"	margin-top: 20px;" +
			"}"+



			"#sessionid_div" +
			"{" +
			"height: 30px;" +
			"width: 750px;" +
			"color:#FE2E2E;" +
			"}"+


			".session_id{font-size: 13px;}"+


			"#details_div" +
			"{" +
			"	height: 100px;" +
			"	width: 720px;" +
			"	padding-left: 10px;" +
			"	border-bottom: #faac58 thin dotted;" +
			"}"+


			".environment{font-size: 11px;padding-left: 50px;}"+

			".grey{color:#6E6E6E;font-size: 11px;}"+

			"#session_details{height: auto;width: 720px;min-height:340px;margin-top: 10px;margin-bottom: 10px;}"+

			"#session_details td{border-bottom: thin grey solid;}"


			; 


		try 
		{

			File report= new File(resultFolder+sessionId+"\\report.css");
			if(!report.exists())
				report.createNewFile();

			FileWriter fr= new FileWriter(report);
			fr.write(css);
			fr.flush();
			fr.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	private void createHtmlReport(String sessionId)
	{
		createCss(sessionId);

		Properties prop = new Properties();
		Properties started = new Properties();
		Properties ended = new Properties();
		try 
		{
			prop.load(new FileInputStream(new File(resultFolder+sessionId+"\\config.properties")));
			started.load(new FileInputStream(new File(resultFolder+sessionId+"\\started.properties")));
			ended.load(new FileInputStream(new File(resultFolder+sessionId+"\\ended.properties")));
		} 
		catch (FileNotFoundException e1) 
		{

			e1.printStackTrace();
		} catch (IOException e1) 
		{

			e1.printStackTrace();
		}

		String tillHead= 
			"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"+
			"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"><title>Session Details: "+sessionId+"</title>"+
			"<link type=\"text/css\" rel=\"stylesheet\" href=\"report.css\"></head>";


		String main_div=
			"<body>" +
			"<div id=\"main_div\">";

		String inner_div=
			"<div id=\"inner_div\">" +
			"<div id=\"sessionid_div\">"+
			"<table>" +
			"<tr>" +
			"<td class=\"session_id\"><span style=\"color:#6E6E6E\">Sessionid:&nbsp</span>"+sessionId+"</td>"+

			"</tr>"+
			"</table>"+

			"</div><!-- sessionid_div -->"+

			"<div id=\"details_div\">"+
			"<table>"+
			"<tr>"+
			"<td class=\"grey\">Started:</td><td style=\"font-size:13px \">"+started.getProperty("started")+"</td>"+
			"</tr>"+
			"<tr>"+
			"<td class=\"grey\" >Ended:</td><td  style=\"font-size:13px\">"+ended.getProperty("ended")+"</td>"+
			"</tr>"+

			"<tr>"+
			"<td class=\"grey\" >Execution Environment:</td><td  style=\"font-size:13px\">"+prop.getProperty("browser")+"&nbsp"+prop.getProperty("version")+" in "+prop.getProperty("platform")+"</td>"+
			"</tr>"+

			/*"<tr>"+
							"<td class=\"grey\" >Video log:</td><td  style=\"font-size:13px\">"+"<a href=\"video.flv\">Video.flv</a>"+"</td>"+
							"</tr>"+*/

			"</table>"+
			"</div><!-- details_div  -->"+
			"<div id=\"session_details\">"+
			"<table style=\"font-size:13px;\">"+
			"<tr>"+
			"<td><div style=\"width: 300px\">Command</div></td>"+
			"<td><div style=\"width: 300px\">Response</div></td>"+
			"<td><div style=\"width: 70px\">Duration</div></td>"+
			"<td><div style=\"width: 70px\">Screen</div></td>"+
			"</tr>"	+

			"<!-- The details of each session adds here -->"
			;

		String close="</table>"+

		"</div><!-- session_details  -->"+

		"</div><!-- inner_div -->"+

		"</div><!-- main_div -->"+
		"</body>"+
		"</html>";

		try 
		{
			String tableData= FileUtils.readFileToString(new File(resultFolder+sessionId+"\\data.txt"));
			String htmlReport=tillHead+main_div+inner_div+tableData+close;

			File report= new File(resultFolder+sessionId+"\\report.html");
			if(!report.exists())
				report.createNewFile();

			FileWriter fr= new FileWriter(report);
			fr.write(htmlReport);
			fr.flush();
			fr.close();
		} 
		catch (IOException e) {
			e.printStackTrace();
		}	 

	}
	protected class RemoteWebDriverOptions implements Options {

		@Beta
		public Logs logs() {
			return remoteLogs;
		}

		public void addCookie(Cookie cookie) {
			execute(DriverCommand.ADD_COOKIE, ImmutableMap.of("cookie", cookie));
		}

		public void deleteCookieNamed(String name) {
			execute(DriverCommand.DELETE_COOKIE, ImmutableMap.of("name", name));
		}

		public void deleteCookie(Cookie cookie) {
			deleteCookieNamed(cookie.getName());
		}

		public void deleteAllCookies() {
			execute(DriverCommand.DELETE_ALL_COOKIES);
		}

		@SuppressWarnings({"unchecked"})
		public Set<Cookie> getCookies() {
			Object returned = execute(DriverCommand.GET_ALL_COOKIES).getValue();

			List<Map<String, Object>> cookies =
				new JsonToBeanConverter().convert(List.class, returned);
			Set<Cookie> toReturn = new HashSet<Cookie>();
			for (Map<String, Object> rawCookie : cookies) {
				String name = (String) rawCookie.get("name");
				String value = (String) rawCookie.get("value");
				String path = (String) rawCookie.get("path");
				String domain = (String) rawCookie.get("domain");
				boolean secure = rawCookie.containsKey("secure") && (Boolean) rawCookie.get("secure");

				Number expiryNum = (Number) rawCookie.get("expiry");
				Date expiry = expiryNum == null ? null : new Date(
						TimeUnit.SECONDS.toMillis(expiryNum.longValue()));

				toReturn.add(new Cookie.Builder(name, value)
				.path(path)
				.domain(domain)
				.isSecure(secure)
				.expiresOn(expiry)
				.build());
			}

			return toReturn;
		}

		public Cookie getCookieNamed(String name) {
			Set<Cookie> allCookies = getCookies();
			for (Cookie cookie : allCookies) {
				if (cookie.getName().equals(name)) {
					return cookie;
				}
			}
			return null;
		}

		public Timeouts timeouts() {
			return new RemoteTimeouts();
		}

		public ImeHandler ime() {
			return new RemoteInputMethodManager();
		}

		@Beta
		public Window window() {
			return new RemoteWindow();
		}

		protected class RemoteInputMethodManager implements WebDriver.ImeHandler {

			@SuppressWarnings("unchecked")
			public List<String> getAvailableEngines() {
				Response response = execute(DriverCommand.IME_GET_AVAILABLE_ENGINES);
				return (List<String>) response.getValue();
			}

			public String getActiveEngine() {
				Response response = execute(DriverCommand.IME_GET_ACTIVE_ENGINE);
				return (String) response.getValue();
			}

			public boolean isActivated() {
				Response response = execute(DriverCommand.IME_IS_ACTIVATED);
				return (Boolean) response.getValue();
			}

			public void deactivate() {
				execute(DriverCommand.IME_DEACTIVATE);
			}

			public void activateEngine(String engine) {
				execute(DriverCommand.IME_ACTIVATE_ENGINE, ImmutableMap.of("engine", engine));
			}
		} // RemoteInputMethodManager class

		protected class RemoteTimeouts implements Timeouts {

			public Timeouts implicitlyWait(long time, TimeUnit unit) {
				execute(DriverCommand.IMPLICITLY_WAIT, ImmutableMap.of("ms",
						TimeUnit.MILLISECONDS.convert(Math.max(0, time), unit)));
				return this;
			}

			public Timeouts setScriptTimeout(long time, TimeUnit unit) {
				execute(DriverCommand.SET_SCRIPT_TIMEOUT,
						ImmutableMap.of("ms", TimeUnit.MILLISECONDS.convert(time, unit)));
				return this;
			}

			public Timeouts pageLoadTimeout(long time, TimeUnit unit) {
				execute(DriverCommand.SET_TIMEOUT, ImmutableMap.of(
						"type", "page load",
						"ms", TimeUnit.MILLISECONDS.convert(time, unit)));
				return this;
			}
		} // timeouts class.

		@Beta
		protected class RemoteWindow implements Window {

			public void setSize(Dimension targetSize) {
				execute(DriverCommand.SET_WINDOW_SIZE,
						ImmutableMap.of("windowHandle", "current",
								"width", targetSize.width, "height", targetSize.height));
			}

			public void setPosition(Point targetPosition) {
				execute(DriverCommand.SET_WINDOW_POSITION,
						ImmutableMap
						.of("windowHandle", "current", "x", targetPosition.x, "y", targetPosition.y));
			}

			@SuppressWarnings({"unchecked"})
			public Dimension getSize() {
				Response response = execute(DriverCommand.GET_WINDOW_SIZE,
						ImmutableMap.of("windowHandle", "current"));
				Map<String, Object> rawSize = (Map<String, Object>) response.getValue();

				int width = ((Number) rawSize.get("width")).intValue();
				int height = ((Number) rawSize.get("height")).intValue();

				return new Dimension(width, height);
			}

			@SuppressWarnings({"unchecked"})
			public Point getPosition() {
				Response response = execute(DriverCommand.GET_WINDOW_POSITION,
						ImmutableMap.of("windowHandle", "current"));
				Map<String, Object> rawPoint = (Map<String, Object>) response.getValue();

				int x = ((Number) rawPoint.get("x")).intValue();
				int y = ((Number) rawPoint.get("y")).intValue();

				return new Point(x, y);
			}

			public void maximize() {
				execute(DriverCommand.MAXIMIZE_WINDOW,
						ImmutableMap.of("windowHandle", "current"));
			}
		}
	}

	private class RemoteNavigation implements Navigation {

		public void back() {
			execute(DriverCommand.GO_BACK);
		}

		public void forward() {
			execute(DriverCommand.GO_FORWARD);
		}

		public void to(String url) {
			get(url);
		}

		public void to(URL url) {
			get(String.valueOf(url));
		}

		public void refresh() {
			execute(DriverCommand.REFRESH);
		}
	}

	protected class RemoteTargetLocator implements TargetLocator {

		public WebDriver frame(int frameIndex) {
			execute(DriverCommand.SWITCH_TO_FRAME, ImmutableMap.of("id", frameIndex));
			return RemoteWebDriver.this;
		}

		public WebDriver frame(String frameName) {
			execute(DriverCommand.SWITCH_TO_FRAME, ImmutableMap.of("id", frameName));
			return RemoteWebDriver.this;
		}

		public WebDriver frame(WebElement frameElement) {
			Object elementAsJson = new WebElementToJsonConverter().apply(frameElement);
			execute(DriverCommand.SWITCH_TO_FRAME, ImmutableMap.of("id", elementAsJson));
			return RemoteWebDriver.this;
		}

		public WebDriver window(String windowName) {
			execute(DriverCommand.SWITCH_TO_WINDOW, ImmutableMap.of("name", windowName));
			return RemoteWebDriver.this;
		}

		public WebDriver defaultContent() {
			Map<String, Object> frameId = Maps.newHashMap();
			frameId.put("id", null);
			execute(DriverCommand.SWITCH_TO_FRAME, frameId);
			return RemoteWebDriver.this;
		}

		public WebElement activeElement() {
			Response response = execute(DriverCommand.GET_ACTIVE_ELEMENT);
			return (WebElement) response.getValue();
		}

		public Alert alert() {
			execute(DriverCommand.GET_ALERT_TEXT);
			return new RemoteAlert();
		}

		//@Override
		public WebDriver parentFrame() {
			// TODO Auto-generated method stub
			return null;
		}
	}

	private class RemoteAlert implements Alert {

		public RemoteAlert() {
		}

		public void dismiss() {
			execute(DriverCommand.DISMISS_ALERT);
		}

		public void accept() {
			execute(DriverCommand.ACCEPT_ALERT);
		}

		public String getText() {
			return (String) execute(DriverCommand.GET_ALERT_TEXT).getValue();
		}

		public void sendKeys(String keysToSend) {
			execute(DriverCommand.SET_ALERT_VALUE, ImmutableMap.of("text", keysToSend));
		}

		public void authenticateUsing(Credentials credentials) {
			throw new UnsupportedCommandException("Not implemented yet");
		}
	}

	public enum When {
		BEFORE,
		AFTER,
		EXCEPTION
	}

	@Override
	public String toString() {
		Capabilities caps = getCapabilities();
		if (caps == null) {
			return super.toString();
		}
		return String.format("%s: %s on %s (%s)", getClass().getSimpleName(),
				caps.getBrowserName(), caps.getPlatform(), getSessionId());
	}

	//@Override
	public <X> X getScreenshotAs(OutputType<X> arg0) throws WebDriverException {
		// TODO Auto-generated method stub

		return arg0.convertFromBase64Png(execute(DriverCommand.SCREENSHOT).getValue().toString());

	}
}
